#!/usr/bin/env python
## Copyright (C) 2010, Scott W. Dunlop <swdunlop@gmail.com>
## All rights reserved.
## 
## Redistribution and use in source and binary forms, with or without
## modification, are permitted provided that the following conditions are met:
##    * Redistributions of source code must retain the above copyright
##      notice, this list of conditions and the following disclaimer.
##    * Redistributions in binary form must reproduce the above copyright
##      notice, this list of conditions and the following disclaimer in the
##      documentation and/or other materials provided with the distribution.
##    * Neither the name of the <organization> nor the
##      names of its contributors may be used to endorse or promote products
##      derived from this software without specific prior written permission.
##
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
## ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
## DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
## (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
## LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
## THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
##
## Credit where credit's due -- Phar pointed out a nice data source.
##
## Amusingly, doing this through Twitter's API hits the rate limit fast, but
## Twitter doesn't complain about screen scraping, according to robots.txt..

import urllib, urllib2, re, sys, threading, nogo

MAX_DEPTH=2
TWITTER_URL="http://twitter.com/"
INTERACTIONS_REGEX=re.compile( 
    'a class="tweet-url username" href="/([a-z_A-Z0-9]+)"' 
)

analyzed = set( )

def analyze_ident( ident, depth = None, max_depth = MAX_DEPTH ):
    if depth is None: depth = max_depth
    print "+" + "--" * ( MAX_DEPTH - depth ) + ident
    if depth <= 0: return

    with nogo.control:
        if ident in analyzed: return
        analyzed.add( ident )
    
    url = TWITTER_URL + urllib.quote( ident )
    try:
        text = urllib2.urlopen( url ).read( )
    except urllib2.URLError, e:
        print "While fetching: %r:" % url
        print "     URL Error: %s" % e
        return 
    
    for reference in INTERACTIONS_REGEX.findall( text ):
        reference = reference.lower()
        nogo.link( ident, reference )
        analyze_ident( reference, depth - 1 )

def twitmap( root, depth = MAX_DEPTH ):
    analyze_ident( root, depth, depth )

if __name__ == "__main__":
    if len( sys.argv ) < 2:
        root = "ioactive" # Shameless self promotion..
    else:
        root = sys.argv[1]
    twitmap( root.lower() )

if __name__ == "__main__":
    if len( sys.argv ) < 2:
        twitmap( "ioactive" )
    else:
        for ident in sys.argv[1:]:
            twitmap( ident.lower() )

